package cn.virens.config;

import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.ServletContainerSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import cn.virens.web.components.shiro.SimpleShiroFilterFactoryBean;
import cn.virens.web.components.shiro.cache.spring.SpringCacheManage;
import cn.virens.web.components.shiro.cookie.RememberMeCookie;
import cn.virens.web.components.shiro.simple.SimpleAuthorizingRealm;
import cn.virens.web.components.shiro.simple.ajax.AjaxAuthorizingFilter;
import cn.virens.web.components.shiro.simple.ajax.AjaxLogoutFilter;
import cn.virens.web.components.shiro.simple.ajax.AjaxUserFilter;
import cn.virens.web.components.shiro.simple.oauth2.OauthWebAuthorizingFilter;
import cn.virens.web.components.shiro.simple.simple.SimpleAuthorizingFilter;
import cn.virens.web.components.shiro.simple.simple.SimpleLogoutFilter;
import cn.virens.web.components.shiro.simple.simple.SimpleUserFilter;

/**
 * 权限框架配置
 * 
 * @作者   : virens
 * @创建时间 :2017年8月1日 下午1:37:08
 */
@Configuration
public class SpringShiroConfig {

	@Value("${auth.api.url.user}")
	private String apiUserUrl;

	@Value("${auth.api.url.login}")
	private String apiLoginUrl;

	@Value("${auth.api.url.logout}")
	private String apiLogoutUrl;

	@Value("${auth.simple.url.user}")
	private String simpleUserUrl;

	@Value("${auth.simple.url.login}")
	private String simpleLoginUrl;

	@Value("${auth.simple.url.logout}")
	private String simpleLogoutUrl;

	@Value("${auth.simple.url.success}")
	private String simpleSuccessUrl;

	@Value("${auth.simple.url.redirect}")
	private String simpleRedirectUrl;

	@Value("${auth.oauth.url.web.login}")
	private String oauthLoginWebUrl;

	@Value("${auth.oauth.url.ajax.login}")
	private String oauthLoginAjaxUrl;

	@Value("${auth.captcha}")
	private Boolean captcha;

	@Value("${auth.param.captcha}")
	private String captchaName;

	@Value("${auth.param.username}")
	private String usernameName;

	@Value("${auth.param.password}")
	private String passwordName;

	@Value("${auth.param.rememberme}")
	private String rememberMeName;

	@Value("${auth.param.failurekey}")
	private String failureKeyAttribute;

	/**
	 * Shiro 缓存管理器配置
	 * 
	 * @param  cacheManager
	 * @return
	 */
	@Bean("shiro-cachemanager")
	public SpringCacheManage springCacheManage(org.springframework.cache.CacheManager cacheManager) {
		return new SpringCacheManage(cacheManager);
	}

	/**
	 * 会话管理器
	 * 
	 * @param  sessionDAO
	 * @return
	 */
	@Bean("shiro-sessionmanager")
	public ServletContainerSessionManager sessionManager() {
		return new ServletContainerSessionManager();
	}

	/**
	 * Realm实现
	 * 
	 * @param  authorizingProvider
	 * @return
	 */
	@Bean("shiro-simple-realm")
	public SimpleAuthorizingRealm authorizingRealm() {
		SimpleAuthorizingRealm realm = new SimpleAuthorizingRealm();
		realm.setAuthenticationCacheName("shiro-authentication");
		realm.setAuthorizationCacheName("shiro-authorization");
		realm.setAuthenticationCachingEnabled(true);
		realm.setAuthorizationCachingEnabled(true);

		return realm;
	}

	/**
	 * rememberMe管理器
	 * 
	 * @return
	 */
	@Bean("shiro-remembermemanager")
	public CookieRememberMeManager rememberMeManager() {
		CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
		rememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
		rememberMeManager.setCookie(new RememberMeCookie());

		return rememberMeManager;
	}

	/**
	 * 安全管理器
	 * 
	 * @return
	 */
	@Bean("shiro-securitymanager")
	public DefaultWebSecurityManager securityManager(//
			@Qualifier("shiro-simple-realm") Realm realm, //
			@Qualifier("shiro-cachemanager") SpringCacheManage cacheManager, //
			@Qualifier("shiro-sessionmanager") SessionManager sessionManager, //
			@Qualifier("shiro-remembermemanager") RememberMeManager rememberMeManager) {

		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRememberMeManager(rememberMeManager);
		securityManager.setSessionManager(sessionManager);
		securityManager.setCacheManager(cacheManager);
		securityManager.setRealm(realm);

		return securityManager;
	}

	/** Shiro的Web过滤器 */
	@Bean("springShiroSecurityFilter")
	public ShiroFilterFactoryBean shiroFilter(@Qualifier("shiro-securitymanager") SecurityManager securityManager) throws Exception {
		SimpleShiroFilterFactoryBean factoryBean = new SimpleShiroFilterFactoryBean();
		factoryBean.setSecurityManager(securityManager);

		factoryBean.addFilter("simpleAuthorizingFilter", simpleAuthorizingFilter());
		factoryBean.addFilter("simpleLogoutFilter", simpleLogoutFilter());
		factoryBean.addFilter("simpleUserFilter", simpleUserFilter());

		factoryBean.addFilter("oauthWebAuthorizingFilter", oauthWebAuthorizingFilter());

		factoryBean.addFilter("ajaxAuthorizingFilter", ajaxAuthorizingFilter());
		factoryBean.addFilter("ajaxLogoutFilter", ajaxLogoutFilter());
		factoryBean.addFilter("ajaxUserFilter", ajaxUserFilter());

		// 网页登录
		factoryBean.addFilterChain(simpleLoginUrl, "simpleAuthorizingFilter");
		factoryBean.addFilterChain(simpleLogoutUrl, "simpleLogoutFilter");
		factoryBean.addFilterChain(simpleUserUrl, "simpleUserFilter");

		// 第三方登录
		factoryBean.addFilterChain(oauthLoginWebUrl, "oauthWebAuthorizingFilter");

		// Ajax接口登录
		factoryBean.addFilterChain(apiLoginUrl, "ajaxAuthorizingFilter");
		factoryBean.addFilterChain(apiLogoutUrl, "ajaxLogoutFilter");
		factoryBean.addFilterChain(apiUserUrl, "ajaxUserFilter");
		factoryBean.addFilterChain("/**", "anon");

		return factoryBean;
	}

	/**
	 * 授权 注解配置
	 * 
	 * @return
	 */
	@Bean
	public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
		return new DefaultAdvisorAutoProxyCreator();
	}

	/**
	 * 授权 注解配置
	 * 
	 * @return
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor attributeSourceAdvisor(@Qualifier("shiro-securitymanager") SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		attributeSourceAdvisor.setSecurityManager(securityManager);

		return attributeSourceAdvisor;
	}

	@Bean
	public AjaxUserFilter ajaxUserFilter() {
		AjaxUserFilter ajaxUserFilter = new AjaxUserFilter();
		ajaxUserFilter.setLoginUrl(apiLoginUrl);

		return ajaxUserFilter;
	}

	@Bean
	public AjaxLogoutFilter ajaxLogoutFilter() {
		return new AjaxLogoutFilter();
	}

	@Bean
	public AjaxAuthorizingFilter ajaxAuthorizingFilter() {
		AjaxAuthorizingFilter ajaxFormFilter = new AjaxAuthorizingFilter();
		ajaxFormFilter.setPasswordParam(passwordName);
		ajaxFormFilter.setUsernameParam(usernameName);
		ajaxFormFilter.setCaptchaParam(captchaName);
		ajaxFormFilter.setLoginUrl(apiLoginUrl);
		ajaxFormFilter.setUseCaptcha(captcha);

		return ajaxFormFilter;
	}

	@Bean
	public OauthWebAuthorizingFilter oauthWebAuthorizingFilter() {
		OauthWebAuthorizingFilter simpleAuthcFilter = new OauthWebAuthorizingFilter();
		simpleAuthcFilter.setFailureKeyAttribute(failureKeyAttribute);
		simpleAuthcFilter.setSuccessUrl(simpleSuccessUrl);
		simpleAuthcFilter.setLoginUrl(oauthLoginWebUrl);

		return simpleAuthcFilter;
	}

	@Bean
	public SimpleUserFilter simpleUserFilter() {
		SimpleUserFilter simpleUserFilter = new SimpleUserFilter();
		simpleUserFilter.setLoginUrl(simpleLoginUrl);

		return simpleUserFilter;
	}

	@Bean
	public SimpleLogoutFilter simpleLogoutFilter() {
		SimpleLogoutFilter simpleLogoutFilter = new SimpleLogoutFilter();
		simpleLogoutFilter.setRedirectUrl(simpleRedirectUrl);

		return simpleLogoutFilter;
	}

	@Bean
	public SimpleAuthorizingFilter simpleAuthorizingFilter() {
		SimpleAuthorizingFilter simpleAuthcFilter = new SimpleAuthorizingFilter();
		simpleAuthcFilter.setFailureKeyAttribute(failureKeyAttribute);
		simpleAuthcFilter.setRememberMeParam(rememberMeName);
		simpleAuthcFilter.setPasswordParam(passwordName);
		simpleAuthcFilter.setUsernameParam(usernameName);
		simpleAuthcFilter.setCaptchaParam(captchaName);

		simpleAuthcFilter.setSuccessUrl(simpleSuccessUrl);
		simpleAuthcFilter.setLoginUrl(simpleLoginUrl);
		simpleAuthcFilter.setUseCaptcha(captcha);

		return simpleAuthcFilter;
	}
}